"use client";

import type React from "react";
import {
  useCallback,
  useEffect,
  useRef,
  useState,
  type ChangeEvent,
  type DragEvent,
  type InputHTMLAttributes,
} from "react";

import { type UploadFunction } from "~/core/api/upload";

export type FileMetadata = {
  name: string;
  size: number;
  type: string;
  url: string;
  id: string;
};

export type UploadStatus = "pending" | "uploading" | "success" | "error";

export type FileWithPreview = {
  file: File | FileMetadata;
  id: string;
  preview?: string;
  uploadStatus?: UploadStatus;
  uploadProgress?: number; // 上传进度百分比 (0-100)
};

export type FileUploadOptions = {
  maxFiles?: number; // 仅在multiple为true时使用，默认为无限
  maxSize?: number; // 以字节为单位
  accept?: string;
  multiple?: boolean; // 默认为false
  initialFiles?: FileMetadata[];
  onFilesChange?: (files: FileWithPreview[]) => void; // 文件变化时的回调
  onFilesAdded?: (addedFiles: FileWithPreview[]) => void; // 新文件添加时的回调
  autoUpload?: boolean; // 是否自动上传，默认为true
  uploadFunction: UploadFunction; // 上传方法
  uploadParams?: Record<string, string>; // 上传参数
  onUploadProgress?: (fileId: string, progress: number) => void; // 上传进度回调
  onUploadComplete?: (fileId: string, result: { success: boolean }) => void; // 上传完成回调
};

export type FileUploadState = {
  files: FileWithPreview[];
  isDragging: boolean;
  errors: string[];
};

export type FileUploadActions = {
  addFiles: (files: FileList | File[]) => void;
  removeFile: (id: string) => void;
  clearFiles: () => void;
  clearErrors: () => void;
  retryUpload: (fileId: string) => void;
  handleDragEnter: (e: DragEvent<HTMLElement>) => void;
  handleDragLeave: (e: DragEvent<HTMLElement>) => void;
  handleDragOver: (e: DragEvent<HTMLElement>) => void;
  handleDrop: (e: DragEvent<HTMLElement>) => void;
  handleFileChange: (e: ChangeEvent<HTMLInputElement>) => void;
  openFileDialog: () => void;
  getInputProps: (
    props?: InputHTMLAttributes<HTMLInputElement>,
  ) => InputHTMLAttributes<HTMLInputElement> & {
    ref: React.Ref<HTMLInputElement>;
  };
};

export const useFileUpload = (
  options: FileUploadOptions,
): [FileUploadState, FileUploadActions] => {
  const {
    maxFiles = Infinity,
    maxSize = Infinity,
    accept = "*",
    multiple = false,
    initialFiles = [],
    onFilesChange,
    onFilesAdded,
    autoUpload = true,
    uploadFunction,
    uploadParams = {},
    onUploadProgress,
    onUploadComplete,
  } = options;

  const [state, setState] = useState<FileUploadState>({
    files: initialFiles.map((file) => ({
      file,
      id: file.id,
      preview: file.url,
    })),
    isDragging: false,
    errors: [],
  });

  const inputRef = useRef<HTMLInputElement>(null);

  // 统一的状态更新函数
  const updateState = useCallback(
    (updater: (prev: FileUploadState) => FileUploadState) => {
      setState((prev) => {
        const newState = updater(prev);
        onFilesChange?.(newState.files);
        return newState;
      });
    },
    [onFilesChange],
  );

  // 上传单个文件
  const uploadFile = useCallback(
    async (fileWithPreview: FileWithPreview) => {
      if (!(fileWithPreview.file instanceof File)) return;

      const fileId = fileWithPreview.id;

      // 更新文件状态为上传中
      updateState((prev) => ({
        ...prev,
        files: prev.files.map((f) =>
          f.id === fileId
            ? {
                ...f,
                uploadStatus: "uploading" as UploadStatus,
                uploadProgress: 0,
              }
            : f,
        ),
      }));

      try {
        const result = await uploadFunction({
          file: fileWithPreview.file,
          onProgress: (progress) => {
            // 更新上传进度
            updateState((prev) => ({
              ...prev,
              files: prev.files.map((f) =>
                f.id === fileId ? { ...f, uploadProgress: progress } : f,
              ),
            }));
            onUploadProgress?.(fileId, progress);
          },
          params: uploadParams,
        });

        // 更新文件状态
        updateState((prev) => ({
          ...prev,
          files: prev.files.map((f) =>
            f.id === fileId
              ? {
                  ...f,
                  uploadStatus: result.success
                    ? "success"
                    : ("error" as UploadStatus),
                  uploadProgress: result.success ? 100 : undefined,
                }
              : f,
          ),
        }));

        onUploadComplete?.(fileId, result);
      } catch (error) {
        console.log("上传失败", error);
        updateState((prev) => ({
          ...prev,
          files: prev.files.map((f) =>
            f.id === fileId
              ? {
                  ...f,
                  uploadStatus: "error" as UploadStatus,
                  uploadProgress: undefined,
                }
              : f,
          ),
        }));

        onUploadComplete?.(fileId, { success: false });
      }
    },
    [
      updateState,
      uploadFunction,
      uploadParams,
      onUploadComplete,
      onUploadProgress,
    ],
  );

  useEffect(() => {
    console.log("state", JSON.stringify(state));
  }, [state]);

  // 重试上传
  const retryUpload = useCallback(
    (fileId: string) => {
      const fileToRetry = state.files.find((f) => f.id === fileId);
      if (fileToRetry && fileToRetry.file instanceof File) {
        void uploadFile(fileToRetry);
      }
    },
    [state.files, uploadFile],
  );

  const validateFile = useCallback(
    (file: File | FileMetadata): string | null => {
      if (file instanceof File) {
        if (file.size > maxSize) {
          return `文件 "${file.name}" 超过最大大小 ${formatBytes(maxSize)}。`;
        }
      } else {
        if (file.size > maxSize) {
          return `文件 "${file.name}" 超过最大大小 ${formatBytes(maxSize)}。`;
        }
      }

      if (accept !== "*") {
        const acceptedTypes = accept.split(",").map((type) => type.trim());
        const fileType = file instanceof File ? file.type || "" : file.type;
        const fileExtension = `.${file instanceof File ? file.name.split(".").pop() : file.name.split(".").pop()}`;

        const isAccepted = acceptedTypes.some((type) => {
          if (type.startsWith(".")) {
            return fileExtension.toLowerCase() === type.toLowerCase();
          }
          if (type.endsWith("/*")) {
            const baseType = type.split("/")[0];
            return fileType.startsWith(`${baseType}/`);
          }
          return fileType === type;
        });

        if (!isAccepted) {
          return `文件 "${file instanceof File ? file.name : file.name}" 不是可接受的文件类型。`;
        }
      }

      return null;
    },
    [accept, maxSize],
  );

  const createPreview = useCallback(
    (file: File | FileMetadata): string | undefined => {
      if (file instanceof File) {
        return URL.createObjectURL(file);
      }
      return file.url;
    },
    [],
  );

  const generateUniqueId = useCallback((file: File | FileMetadata): string => {
    if (file instanceof File) {
      return `${file.name}-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
    }
    return file.id;
  }, []);

  const clearFiles = useCallback(() => {
    updateState((prev) => {
      // 清理对象URL
      prev.files.forEach((file) => {
        if (
          file.preview &&
          file.file instanceof File &&
          file.file.type.startsWith("image/")
        ) {
          URL.revokeObjectURL(file.preview);
        }
      });

      if (inputRef.current) {
        inputRef.current.value = "";
      }

      return {
        ...prev,
        files: [],
        errors: [],
      };
    });
  }, [updateState]);

  const addFiles = useCallback(
    (newFiles: FileList | File[]) => {
      if (!newFiles || newFiles.length === 0) return;

      const newFilesArray = Array.from(newFiles);
      const errors: string[] = [];

      // 上传新文件时清除现有错误
      updateState((prev) => ({ ...prev, errors: [] }));

      // 在单文件模式下，先清除现有文件
      if (!multiple) {
        clearFiles();
      }

      // 检查添加这些文件是否会超过最大文件数（仅在多文件模式下）
      if (
        multiple &&
        maxFiles !== Infinity &&
        state.files.length + newFilesArray.length > maxFiles
      ) {
        errors.push(`您最多只能上传 ${maxFiles} 个文件。`);
        updateState((prev) => ({ ...prev, errors }));
        return;
      }

      const validFiles: FileWithPreview[] = [];

      newFilesArray.forEach((file) => {
        // 仅在允许多文件时检查重复
        if (multiple) {
          const isDuplicate = state.files.some(
            (existingFile) =>
              existingFile.file.name === file.name &&
              existingFile.file.size === file.size,
          );

          // 静默跳过重复文件
          if (isDuplicate) {
            return;
          }
        }

        // 检查文件大小
        if (file.size > maxSize) {
          errors.push(
            multiple
              ? `部分文件超过最大大小 ${formatBytes(maxSize)}。`
              : `文件超过最大大小 ${formatBytes(maxSize)}。`,
          );
          return;
        }

        const error = validateFile(file);
        if (error) {
          errors.push(error);
        } else {
          validFiles.push({
            file,
            id: generateUniqueId(file),
            preview: createPreview(file),
            uploadStatus: "pending" as UploadStatus,
            uploadProgress: 0,
          });
        }
      });

      // 仅在有有效文件要添加时更新状态
      if (validFiles.length > 0) {
        // 调用onFilesAdded回调，传入新添加的有效文件
        onFilesAdded?.(validFiles);

        updateState((prev) => ({
          ...prev,
          files: !multiple ? validFiles : [...prev.files, ...validFiles],
          errors,
        }));

        // 如果启用自动上传，开始上传文件
        if (autoUpload) {
          validFiles.forEach((fileWithPreview) => {
            if (fileWithPreview.file instanceof File) {
              void uploadFile(fileWithPreview);
            }
          });
        }
      } else if (errors.length > 0) {
        updateState((prev) => ({
          ...prev,
          errors,
        }));
      }

      // 处理文件后重置输入值
      if (inputRef.current) {
        inputRef.current.value = "";
      }
    },
    [
      updateState,
      multiple,
      maxFiles,
      state.files,
      clearFiles,
      maxSize,
      validateFile,
      generateUniqueId,
      createPreview,
      onFilesAdded,
      autoUpload,
      uploadFile,
    ],
  );

  const removeFile = useCallback(
    (id: string) => {
      updateState((prev) => {
        const fileToRemove = prev.files.find((file) => file.id === id);
        if (
          fileToRemove?.preview &&
          fileToRemove.file instanceof File &&
          fileToRemove.file.type.startsWith("image/")
        ) {
          URL.revokeObjectURL(fileToRemove.preview);
        }

        return {
          ...prev,
          files: prev.files.filter((file) => file.id !== id),
          errors: [],
        };
      });
    },
    [updateState],
  );

  const clearErrors = useCallback(() => {
    updateState((prev) => ({
      ...prev,
      errors: [],
    }));
  }, [updateState]);

  const handleDragEnter = useCallback(
    (e: DragEvent<HTMLElement>) => {
      e.preventDefault();
      e.stopPropagation();
      updateState((prev) => ({ ...prev, isDragging: true }));
    },
    [updateState],
  );

  const handleDragLeave = useCallback(
    (e: DragEvent<HTMLElement>) => {
      e.preventDefault();
      e.stopPropagation();

      if (e.currentTarget.contains(e.relatedTarget as Node)) {
        return;
      }

      updateState((prev) => ({ ...prev, isDragging: false }));
    },
    [updateState],
  );

  const handleDragOver = useCallback((e: DragEvent<HTMLElement>) => {
    e.preventDefault();
    e.stopPropagation();
  }, []);

  const handleDrop = useCallback(
    (e: DragEvent<HTMLElement>) => {
      e.preventDefault();
      e.stopPropagation();
      updateState((prev) => ({ ...prev, isDragging: false }));

      // 如果输入被禁用，则不处理文件
      if (inputRef.current?.disabled) {
        return;
      }

      if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
        // 在单文件模式下，仅使用第一个文件
        if (!multiple) {
          const file = e.dataTransfer.files[0];
          if (file) addFiles([file]);
        } else {
          addFiles(e.dataTransfer.files);
        }
      }
    },
    [updateState, addFiles, multiple],
  );

  const handleFileChange = useCallback(
    (e: ChangeEvent<HTMLInputElement>) => {
      if (e.target.files && e.target.files.length > 0) {
        addFiles(e.target.files);
      }
    },
    [addFiles],
  );

  const openFileDialog = useCallback(() => {
    if (inputRef.current) {
      inputRef.current.click();
    }
  }, []);

  const getInputProps = useCallback(
    (props: InputHTMLAttributes<HTMLInputElement> = {}) => {
      return {
        ...props,
        type: "file" as const,
        onChange: handleFileChange,
        accept: props.accept ?? accept,
        multiple: props.multiple ?? multiple,
        ref: inputRef,
      };
    },
    [accept, multiple, handleFileChange],
  );

  return [
    state,
    {
      addFiles,
      removeFile,
      clearFiles,
      clearErrors,
      retryUpload,
      handleDragEnter,
      handleDragLeave,
      handleDragOver,
      handleDrop,
      handleFileChange,
      openFileDialog,
      getInputProps,
    },
  ];
};

// 辅助函数：将字节格式化为人类可读格式
export const formatBytes = (bytes: number, decimals = 2): string => {
  if (bytes === 0) return "0 字节";

  const k = 1024;
  const dm = decimals < 0 ? 0 : decimals;
  const sizes = ["字节", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];

  const i = Math.floor(Math.log(bytes) / Math.log(k));

  return (
    Number.parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + (sizes[i] ?? "")
  );
};
